﻿using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;

namespace System
{
    public static class StringExtensions
    {
        #region 正则
        /// <summary>
        /// 数字正则
        /// </summary>
        public const string RegexString = "^[a-zA-Z]+$";

        /// <summary>
        /// 字母(大小写)正则
        /// </summary>
        public const string RegexNumber = "^\\d+$";
        #endregion

        /// <summary>
        /// string To Int
        /// </summary>
        /// <param name="source">字符串g</param>
        /// <param name="defaultValue">默认值</param>
        /// <returns>System.Int32.</returns>
        public static int ToInt32(this string source, int defaultValue = 0)
        {
            int result = defaultValue;
            if (int.TryParse(source, out int num))
            {
                result = num;
            }
            return result;
        }

        /// <summary>
        /// string 转换 Int64
        /// </summary>
        /// <param name="source">string</param>
        /// <param name="defaultValue"></param>
        /// <returns>System.Int64.</returns>
        public static long ToInt64(this string source, long defaultValue = 0L)
        {
            long result = defaultValue;
            if (long.TryParse(source, out long num))
            {
                result = num;
            }
            return result;
        }

        /// <summary>
        /// string 转换 Decimal
        /// </summary>
        /// <param name="source">string</param>
        /// <param name="defaultValue"></param>
        /// <returns>System.Decimal.</returns>
        public static decimal ToDecimal(this string source, decimal defaultValue = 0)
        {
            decimal result = defaultValue;
            if (decimal.TryParse(source, out decimal num))
            {
                result = num;
            }
            return result;
        }

        /// <summary>
        /// string 转换 Double
        /// </summary>
        /// <param name="source">string</param>
        /// <param name="defaultValue"></param>
        /// <returns>System.Double.</returns>
        public static double ToDouble(this string source, double defaultValue = 0.0)
        {
            double result = defaultValue;
            if (double.TryParse(source, out double num))
            {
                result = num;
            }
            return result;
        }

        /// <summary>
        /// To the float.
        /// </summary>
        /// <param name="source">The source.</param>
        /// <param name="defaultValue">The default value.</param>
        /// <returns>System.Single.</returns>
        public static float ToFloat(this string source, float defaultValue = 0)
        {
            float result = defaultValue;
            if (float.TryParse(source, out float num))
            {
                result = num;
            }
            return result;
        }

        /// <summary>
        /// string 转换 Boolean
        /// </summary>
        /// <param name="source">string</param>
        /// <param name="defaultValue"></param>
        public static bool ToBool(this string source, bool defaultValue = false)
        {
            bool result;
            if (bool.TryParse(source, out bool flag))
            {
                result = flag;
            }
            else
            {
                switch (source)
                {
                    case "0":
                        result = false;
                        break;
                    case "1":
                        result = true;
                        break;
                    default:
                        result = defaultValue;
                        break;
                }
            }
            return result;
        }

        /// <summary>
        /// string 转换 2次幂总和
        /// </summary>
        /// <param name="source">string</param>
        /// <param name="defaultValue"></param>
        /// <returns>System.Int32.</returns>
        public static int ToPowInt(this string source, char spit = ',')
        {
            var tempInfos = source.Split(spit);
            int num = tempInfos.ToPowInt();
            return num;
        }

        /// <summary>
        /// string 转换 2次幂总和
        /// </summary>
        /// <param name="source">string</param>
        /// <param name="defaultValue"></param>
        /// <returns>System.Int32.</returns>
        public static int ToPowInt(this string[] source)
        {
            int num = 0;
            foreach (var item in source)
            {
                num += (int)Math.Pow(2, item.ToInt32());
            }
            return num;
        }

        /// <summary>
        /// string集合转换带间隔的string
        /// </summary>
        /// <param name="source">string</param>
        /// <param name="defaultValue"></param>
        /// <returns>System.Int32.</returns>
        public static string ToStringSpit(this List<string> source, string spit = ",")
        {
            return string.Join(spit, source);
        }

        /// <summary>
        /// string 转换 DateTime
        /// </summary>
        /// <param name="source">string</param>
        /// <param name="defaultValue"></param>
        /// <returns>DateTime.</returns>
        public static DateTime ToDateTime(this string source, DateTime defaultValue = default)
        {
            DateTime now;
            DateTime result = defaultValue;
            if (DateTime.TryParse(source, out now))
            {
                result = now;
            }
            return result;
        }

        /// <summary>
        /// string 转化为 枚举对象
        /// </summary>
        /// <typeparam name="T">目标类型</typeparam>
        /// <param name="value">待转化的string</param>
        /// <returns>T.</returns>
        public static (bool,T) ToEnum<T>(this string value) where T : struct
        {
            Type typeFromHandle = typeof(T);
            if (!typeFromHandle.IsEnum)
            {
                throw new ArgumentException(string.Format("类型{0}不是枚举类型。", typeFromHandle.Name));
            }
            var isOK = Enum.TryParse(value, out T result);
            return (isOK, result);
        }

        /// <summary>
        /// string 是否为 null 或 empty
        /// </summary>
        /// <param name="source">字符串</param>
        /// <param name="ignoreWhiteSpace"></param>
        /// <returns>bool</returns>
        public static bool IsNullOrWhiteSpace(this string source)
        {
            bool result = string.IsNullOrWhiteSpace(source);
            return result;
        }

        /// <summary>
        /// string 是否为 null 或 empty
        /// </summary>
        /// <param name="source">字符串</param>
        /// <param name="ignoreWhiteSpace"></param>
        /// <returns>bool</returns>
        public static bool IsNotNullOrWhiteSpace(this string source)
        {
            bool result = !string.IsNullOrWhiteSpace(source);
            return result;
        }

        /// <summary>
        /// string 是否为 数字
        /// </summary>
        /// <param name="source">字符串</param>
        /// <returns>bool</returns>
        public static bool IsRegexNumber(this string source)
        {
            bool result = Regex.Match(source, RegexNumber).Success;
            return result;
        }

        /// <summary>
        /// string 是否为 字母(大小写)
        /// </summary>
        /// <param name="source">字符串</param>
        /// <returns>bool</returns>
        public static bool IsRegexString(this string source)
        {
            bool result = Regex.Match(source, RegexString).Success;
            return result;
        }

        private static char[] base64CodeArray = new char[]
        {
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
            '0', '1', '2', '3', '4',  '5', '6', '7', '8', '9', '+', '/', '='
        };
        /// <summary>
        /// 是否base64字符串
        /// </summary>
        /// <param name="base64Str">要判断的字符串</param>
        /// <returns></returns>
        public static bool IsBase64(this string base64Str)
        {
            return IsBase64(base64Str, out byte[] bytes);
        }

        /// <summary>
        /// 是否base64字符串
        /// </summary>
        /// <param name="base64Str">要判断的字符串</param>
        /// <param name="bytes">字符串转换成的字节数组</param>
        /// <returns></returns>
        public static bool IsBase64(this string base64Str, out byte[] bytes)
        {
            //string strRegex = "^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$";
            bytes = null;
            if (string.IsNullOrEmpty(base64Str))
                return false;
            else
            {
                if (base64Str.Contains(","))
                    base64Str = base64Str.Split(',')[1];
                if (base64Str.Length % 4 != 0)
                    return false;
                if (base64Str.Any(c => !base64CodeArray.Contains(c)))
                    return false;
            }
            try
            {
                bytes = Convert.FromBase64String(base64Str);
                return true;
            }
            catch (FormatException)
            {
                return false;
            }
        }

        /// <summary>
        /// Unicode转字符串
        /// </summary>
        /// <param name="source">经过Unicode编码的字符串</param>
        /// <returns>正常字符串</returns>
        public static string UnicodeToString(this string source)
        {
            return new Regex(@"\\u([0-9A-F]{4})", RegexOptions.IgnoreCase | RegexOptions.Compiled).Replace(
                         source, x => string.Empty + Convert.ToChar(Convert.ToUInt16(x.Result("$1"), 16)));
        }

        /// <summary> 
        /// 转换为MD5字符串
        /// </summary> 
        /// <returns></returns> 
        public static string ToMD5(this string str, bool isUpper = true)
        {
            string cl = str;
            string pwd = "";
            MD5 md5 = MD5.Create();//实例化一个md5对像
            // 加密后是一个字节类型的数组，这里要注意编码UTF8/Unicode等的选择　
            byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(cl));
            // 通过使用循环，将字节类型的数组转换为字符串，此字符串是常规字符格式化所得
            for (int i = 0; i < s.Length; i++)
            {
                // 将得到的字符串使用十六进制类型格式。格式后的字符是小写的字母，如果使用大写（X）则格式后的字符是大写字符
                pwd = pwd + (isUpper ? s[i].ToString("X2") : s[i].ToString("x2"));
            }
            return pwd;
        }

        /// <summary> 
        /// 转换为MD5字符串
        /// </summary> 
        /// <returns></returns> 
        public static string ToMD5(this char[] str, bool isUpper = true)
        {
            string pwd = "";
            MD5 md5 = MD5.Create();//实例化一个md5对像
            // 加密后是一个字节类型的数组，这里要注意编码UTF8/Unicode等的选择　
            byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(str));
            // 通过使用循环，将字节类型的数组转换为字符串，此字符串是常规字符格式化所得
            for (int i = 0; i < s.Length; i++)
            {
                // 将得到的字符串使用十六进制类型格式。格式后的字符是小写的字母，如果使用大写（X）则格式后的字符是大写字符
                pwd = pwd + (isUpper ? s[i].ToString("X2") : s[i].ToString("x2"));
            }
            return pwd;
        }
    }

}
